---
title: Resonance Audio Unity SDK API Reference
layout: default
exclude_from_menu: true
---
<!DOCTYPE html>
<html devsite>

<head>
  <meta name="project_path" value="/resonance-audio/_project.yaml" />
  <meta name="book_path" value="/resonance-audio/_book.yaml" />
  <meta name="gtm_var" data-key="docType" data-value="reference">
  <title>Source: source.js</title>
  <link href="jsdoc.css" rel="stylesheet">
</head>

<body>
  <div id="jsdoc-body-container">
    <div id="jsdoc-content">
      <div id="jsdoc-content-container">
        <div id="jsdoc-banner" role="banner">
        </div>
        <div id="jsdoc-main" role="main">
          <header class="page-header">
            <h1>Source: source.js</h1>
          </header>
          <article>
            <pre class="prettyprint linenums"><code>/**
 * @license
 * Copyright 2017 Google Inc. All Rights Reserved.
 * Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an &quot;AS IS&quot; BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @file Source model to spatialize an audio buffer.
 * @author Andrew Allen &amp;lt;bitllama@google.com&gt;
 */

&#x27;use strict&#x27;;


// Internal dependencies.
const Directivity &#x3D; require(&#x27;./directivity.js&#x27;);
const Attenuation &#x3D; require(&#x27;./attenuation.js&#x27;);
const Encoder &#x3D; require(&#x27;./encoder.js&#x27;);
const Utils &#x3D; require(&#x27;./utils.js&#x27;);


/**
 * Options for constructing a new Source.
 * @typedef {Object} Source~SourceOptions
 * @property {Float32Array} position
 * The source&#x27;s initial position (in meters), where origin is the center of
 * the room. Defaults to {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}.
 * @property {Float32Array} forward
 * The source&#x27;s initial forward vector. Defaults to
 * {@linkcode Utils.DEFAULT_FORWARD DEFAULT_FORWARD}.
 * @property {Float32Array} up
 * The source&#x27;s initial up vector. Defaults to
 * {@linkcode Utils.DEFAULT_UP DEFAULT_UP}.
 * @property {Number} minDistance
 * Min. distance (in meters). Defaults to
 * {@linkcode Utils.DEFAULT_MIN_DISTANCE DEFAULT_MIN_DISTANCE}.
 * @property {Number} maxDistance
 * Max. distance (in meters). Defaults to
 * {@linkcode Utils.DEFAULT_MAX_DISTANCE DEFAULT_MAX_DISTANCE}.
 * @property {string} rolloff
 * Rolloff model to use, chosen from options in
 * {@linkcode Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}. Defaults to
 * {@linkcode Utils.DEFAULT_ATTENUATION_ROLLOFF DEFAULT_ATTENUATION_ROLLOFF}.
 * @property {Number} gain Input gain (linear). Defaults to
 * {@linkcode Utils.DEFAULT_SOURCE_GAIN DEFAULT_SOURCE_GAIN}.
 * @property {Number} alpha Directivity alpha. Defaults to
 * {@linkcode Utils.DEFAULT_DIRECTIVITY_ALPHA DEFAULT_DIRECTIVITY_ALPHA}.
 * @property {Number} sharpness Directivity sharpness. Defaults to
 * {@linkcode Utils.DEFAULT_DIRECTIVITY_SHARPNESS
 * DEFAULT_DIRECTIVITY_SHARPNESS}.
 * @property {Number} sourceWidth
 * Source width (in degrees). Where 0 degrees is a point source and 360 degrees
 * is an omnidirectional source. Defaults to
 * {@linkcode Utils.DEFAULT_SOURCE_WIDTH DEFAULT_SOURCE_WIDTH}.
 */


/**
 * @class Source
 * @description Source model to spatialize an audio buffer.
 * @param {ResonanceAudio} scene Associated {@link ResonanceAudio
 * ResonanceAudio} instance.
 * @param {Source~SourceOptions} options
 * Options for constructing a new Source.
 */
function Source(scene, options) {
  // Public variables.
  /**
   * Mono (1-channel) input {@link
   * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}.
   * @member {AudioNode} input
   * @memberof Source
   * @instance
   */
  /**
   *
   */

  // Use defaults for undefined arguments.
  if (options &#x3D;&#x3D; undefined) {
    options &#x3D; {};
  }
  if (options.position &#x3D;&#x3D; undefined) {
    options.position &#x3D; Utils.DEFAULT_POSITION.slice();
  }
  if (options.forward &#x3D;&#x3D; undefined) {
    options.forward &#x3D; Utils.DEFAULT_FORWARD.slice();
  }
  if (options.up &#x3D;&#x3D; undefined) {
    options.up &#x3D; Utils.DEFAULT_UP.slice();
  }
  if (options.minDistance &#x3D;&#x3D; undefined) {
    options.minDistance &#x3D; Utils.DEFAULT_MIN_DISTANCE;
  }
  if (options.maxDistance &#x3D;&#x3D; undefined) {
    options.maxDistance &#x3D; Utils.DEFAULT_MAX_DISTANCE;
  }
  if (options.rolloff &#x3D;&#x3D; undefined) {
    options.rolloff &#x3D; Utils.DEFAULT_ROLLOFF;
  }
  if (options.gain &#x3D;&#x3D; undefined) {
    options.gain &#x3D; Utils.DEFAULT_SOURCE_GAIN;
  }
  if (options.alpha &#x3D;&#x3D; undefined) {
    options.alpha &#x3D; Utils.DEFAULT_DIRECTIVITY_ALPHA;
  }
  if (options.sharpness &#x3D;&#x3D; undefined) {
    options.sharpness &#x3D; Utils.DEFAULT_DIRECTIVITY_SHARPNESS;
  }
  if (options.sourceWidth &#x3D;&#x3D; undefined) {
    options.sourceWidth &#x3D; Utils.DEFAULT_SOURCE_WIDTH;
  }

  // Member variables.
  this._scene &#x3D; scene;
  this._position &#x3D; options.position;
  this._forward &#x3D; options.forward;
  this._up &#x3D; options.up;
  this._dx &#x3D; new Float32Array(3);
  this._right &#x3D; Utils.crossProduct(this._forward, this._up);

  // Create audio nodes.
  let context &#x3D; scene._context;
  this.input &#x3D; context.createGain();
  this._directivity &#x3D; new Directivity(context, {
    alpha: options.alpha,
    sharpness: options.sharpness,
  });
  this._toEarly &#x3D; context.createGain();
  this._toLate &#x3D; context.createGain();
  this._attenuation &#x3D; new Attenuation(context, {
    minDistance: options.minDistance,
    maxDistance: options.maxDistance,
    rolloff: options.rolloff,
  });
  this._encoder &#x3D; new Encoder(context, {
    ambisonicOrder: scene._ambisonicOrder,
    sourceWidth: options.sourceWidth,
  });

  // Connect nodes.
  this.input.connect(this._toLate);
  this._toLate.connect(scene._room.late.input);

  this.input.connect(this._attenuation.input);
  this._attenuation.output.connect(this._toEarly);
  this._toEarly.connect(scene._room.early.input);

  this._attenuation.output.connect(this._directivity.input);
  this._directivity.output.connect(this._encoder.input);

  this._encoder.output.connect(scene._listener.input);

  // Assign initial conditions.
  this.setPosition(
    options.position[0], options.position[1], options.position[2]);
  this.input.gain.value &#x3D; options.gain;
};


/**
 * Set source&#x27;s position (in meters), where origin is the center of
 * the room.
 * @param {Number} x
 * @param {Number} y
 * @param {Number} z
 */
Source.prototype.setPosition &#x3D; function(x, y, z) {
  // Assign new position.
  this._position[0] &#x3D; x;
  this._position[1] &#x3D; y;
  this._position[2] &#x3D; z;

  // Handle far-field effect.
  let distance &#x3D; this._scene._room.getDistanceOutsideRoom(
    this._position[0], this._position[1], this._position[2]);
    let gain &#x3D; _computeDistanceOutsideRoom(distance);
  this._toLate.gain.value &#x3D; gain;
  this._toEarly.gain.value &#x3D; gain;

  this._update();
};


// Update the source when changing the listener&#x27;s position.
Source.prototype._update &#x3D; function() {
  // Compute distance to listener.
  for (let i &#x3D; 0; i &amp;lt; 3; i++) {
    this._dx[i] &#x3D; this._position[i] - this._scene._listener.position[i];
  }
  let distance &#x3D; Math.sqrt(this._dx[0] * this._dx[0] +
    this._dx[1] * this._dx[1] + this._dx[2] * this._dx[2]);
  if (distance &gt; 0) {
    // Normalize direction vector.
    this._dx[0] /&#x3D; distance;
    this._dx[1] /&#x3D; distance;
    this._dx[2] /&#x3D; distance;
  }

  // Compuete angle of direction vector.
  let azimuth &#x3D; Math.atan2(-this._dx[0], this._dx[2]) *
    Utils.RADIANS_TO_DEGREES;
  let elevation &#x3D; Math.atan2(this._dx[1], Math.sqrt(this._dx[0] * this._dx[0] +
    this._dx[2] * this._dx[2])) * Utils.RADIANS_TO_DEGREES;

  // Set distance/directivity/direction values.
  this._attenuation.setDistance(distance);
  this._directivity.computeAngle(this._forward, this._dx);
  this._encoder.setDirection(azimuth, elevation);
};


/**
 * Set source&#x27;s rolloff.
 * @param {string} rolloff
 * Rolloff model to use, chosen from options in
 * {@linkcode Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}.
 */
Source.prototype.setRolloff &#x3D; function(rolloff) {
  this._attenuation.setRolloff(rolloff);
};


/**
 * Set source&#x27;s minimum distance (in meters).
 * @param {Number} minDistance
 */
Source.prototype.setMinDistance &#x3D; function(minDistance) {
  this._attenuation.minDistance &#x3D; minDistance;
};


/**
 * Set source&#x27;s maximum distance (in meters).
 * @param {Number} maxDistance
 */
Source.prototype.setMaxDistance &#x3D; function(maxDistance) {
  this._attenuation.maxDistance &#x3D; maxDistance;
};


/**
 * Set source&#x27;s gain (linear).
 * @param {Number} gain
 */
Source.prototype.setGain &#x3D; function(gain) {
  this.input.gain.value &#x3D; gain;
};


/**
 * Set the source&#x27;s orientation using forward and up vectors.
 * @param {Number} forwardX
 * @param {Number} forwardY
 * @param {Number} forwardZ
 * @param {Number} upX
 * @param {Number} upY
 * @param {Number} upZ
 */
Source.prototype.setOrientation &#x3D; function(forwardX, forwardY, forwardZ,
    upX, upY, upZ) {
  this._forward[0] &#x3D; forwardX;
  this._forward[1] &#x3D; forwardY;
  this._forward[2] &#x3D; forwardZ;
  this._up[0] &#x3D; upX;
  this._up[1] &#x3D; upY;
  this._up[2] &#x3D; upZ;
  this._right &#x3D; Utils.crossProduct(this._forward, this._up);
};


// TODO(bitllama): Make sure this works with Three.js as intended.
/**
 * Set source&#x27;s position and orientation using a
 * Three.js modelViewMatrix object.
 * @param {Float32Array} matrix4
 * The Matrix4 representing the object position and rotation in world space.
 */
Source.prototype.setFromMatrix &#x3D; function(matrix4) {
  this._right[0] &#x3D; matrix4.elements[0];
  this._right[1] &#x3D; matrix4.elements[1];
  this._right[2] &#x3D; matrix4.elements[2];
  this._up[0] &#x3D; matrix4.elements[4];
  this._up[1] &#x3D; matrix4.elements[5];
  this._up[2] &#x3D; matrix4.elements[6];
  this._forward[0] &#x3D; matrix4.elements[8];
  this._forward[1] &#x3D; matrix4.elements[9];
  this._forward[2] &#x3D; matrix4.elements[10];

  // Normalize to remove scaling.
  this._right &#x3D; Utils.normalizeVector(this._right);
  this._up &#x3D; Utils.normalizeVector(this._up);
  this._forward &#x3D; Utils.normalizeVector(this._forward);

  // Update position.
  this.setPosition(
    matrix4.elements[12], matrix4.elements[13], matrix4.elements[14]);
};


/**
 * Set the source width (in degrees). Where 0 degrees is a point source and 360
 * degrees is an omnidirectional source.
 * @param {Number} sourceWidth (in degrees).
 */
Source.prototype.setSourceWidth &#x3D; function(sourceWidth) {
  this._encoder.setSourceWidth(sourceWidth);
  this.setPosition(this._position[0], this._position[1], this._position[2]);
};


/**
 * Set source&#x27;s directivity pattern (defined by alpha), where 0 is an
 * omnidirectional pattern, 1 is a bidirectional pattern, 0.5 is a cardiod
 * pattern. The sharpness of the pattern is increased exponentially.
 * @param {Number} alpha
 * Determines directivity pattern (0 to 1).
 * @param {Number} sharpness
 * Determines the sharpness of the directivity pattern (1 to Inf).
 */
Source.prototype.setDirectivityPattern &#x3D; function(alpha, sharpness) {
  this._directivity.setPattern(alpha, sharpness);
  this.setPosition(this._position[0], this._position[1], this._position[2]);
};


/**
 * Determine the distance a source is outside of a room. Attenuate gain going
 * to the reflections and reverb when the source is outside of the room.
 * @param {Number} distance Distance in meters.
 * @return {Number} Gain (linear) of source.
 * @private
 */
function _computeDistanceOutsideRoom(distance) {
  // We apply a linear ramp from 1 to 0 as the source is up to 1m outside.
  let gain &#x3D; 1;
  if (distance &gt; Utils.EPSILON_FLOAT) {
    gain &#x3D; 1 - distance / Utils.SOURCE_MAX_OUTSIDE_ROOM_DISTANCE;

    // Clamp gain between 0 and 1.
    gain &#x3D; Math.max(0, Math.min(1, gain));
  }
  return gain;
}


module.exports &#x3D; Source;
</code></pre>
          </article>
        </div>
      </div>
      <nav id="jsdoc-toc-nav" role="navigation"></nav>
    </div>
  </div>
</body>

</html>
